package com.lin.operatorlogrecord.unit;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.lin.operatorlogrecord.content.OperatorLogRecord;
import com.lin.operatorlogrecord.entity.constant.GlobalConstant;
import com.lin.operatorlogrecord.entity.enums.ObjectTypeEnum;
import com.lin.operatorlogrecord.exception.OperatorLogException;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: chenghao.lin
 * @Date: 2023/09/21
 * @Description: 操作日志工具类
 */
public class OperatorLogUtil {

    /**
     * 通过表对应实体获取表名
     * @param tableEntity
     * @return
     */
    public static String getTableName(Class<?> tableEntity) {
        TableName tableNameAnnotation = tableEntity.getDeclaredAnnotation(TableName.class);
        if (tableNameAnnotation == null) {
            throw new OperatorLogException("该类[" + tableEntity.getName() + "]" + "没有标注TableName注解");
        }
        return tableNameAnnotation.value();
    }

    /**
     * 通过表对应实体获取对象类型枚举
     * @param tableEntity
     * @return
     */
    public static ObjectTypeEnum getObjectTypeEnum(Class<?> tableEntity) {
        String tableName = OperatorLogUtil.getTableName(tableEntity);
        return ObjectTypeEnum.getByTableName(tableName);
    }

    /**
     * 查询对象列表名称
     * @param requestObjs
     * @param tableClass
     * @return
     */
    public static String listObjName(List<String> requestObjs, Class<?> tableClass) {
        // 查询数据
        List<Map<String, Object>> queryList = OperatorLogQueryUtil.listObj(requestObjs, tableClass);
        List<String> result = new ArrayList<>();
        for (Map<String, Object> queryMap : queryList) {
            String name = (String) queryMap.get(GlobalConstant.TABLE_NAME_COLUMN_NAME);
            if (name == null) {
                throw new OperatorLogException("查询对象名列表，该表没有name字段");
            }
            result.add(name);
        }
        return String.join(GlobalConstant.COMMA, result);
    }


    /**
     * 查询对象名称
     * @param operatorObjId
     * @param tableClass
     * @return
     */
    public static String getObjName(String operatorObjId, Class<?> tableClass) {
        // 查询数据
        Map<String, Object> queryMap = OperatorLogQueryUtil.getObj(operatorObjId, tableClass);
        String name = (String) queryMap.get(GlobalConstant.TABLE_NAME_COLUMN_NAME);
        if (name == null) {
            throw new OperatorLogException("查询对象名列表，该表没有name字段");
        }
        return name;
    }

    /**
     * 根据字段优先级排序，并转为String
     * @param records
     * @return
     */
    public static String sortOperatorLogRecord(List<OperatorLogRecord> records) {
        if (CollectionUtils.isEmpty(records)){
            return "";
        }
        records.sort(Comparator.comparingInt(OperatorLogRecord::getPriority));
        return records.stream().map(OperatorLogRecord::getChangeLogContent).collect(Collectors.joining());
    }

    public static Object getObj(Class<?> objClazz, String operatorObjId, Class<?> tableClazz) throws IllegalAccessException, InstantiationException {
        Object result = objClazz.newInstance();
        Field[] resultFields = objClazz.getDeclaredFields();
        List<Field> tableFields = new ArrayList<>(Arrays.asList(tableClazz.getDeclaredFields()));
        // 查询旧数据
        Map<String, Object> queryMap = OperatorLogQueryUtil.getObj(operatorObjId, tableClazz);
        // 设置值
        for (Field resultField : resultFields) {
            Optional<Field> first = tableFields.stream().filter(i -> i.getName().equals(resultField.getName())).findFirst();
            if (first.isPresent()) {
                Field tableField = first.get();
                resultField.setAccessible(true);
                resultField.set(result, getFiledValue(tableField, queryMap));
            }
        }
        return result;
    }

    /**
     * 获取字段值
     * @param tableField
     * @param queryMap
     * @return
     */
    private static Object getFiledValue(Field tableField, Map<String, Object> queryMap) {
        TableField tableFieldAnnotation = tableField.getDeclaredAnnotation(TableField.class);
        if (tableFieldAnnotation == null) {
            return null;
        }
        Object result = queryMap.get(tableFieldAnnotation.value());
        // 特殊处理枚举
        if (tableField.getType().isEnum()) {
            EnumUtils.getIEnumBase(tableField.getType(), (Integer) result);
        }
        return result;
    }
}
